package com.yfqy.app.modules.pay.serviceimpl;

import com.yfqy.app.constant.GeneralConstants;
import com.yfqy.app.constant.RedisKeyConstants;
import com.yfqy.app.domain.entity.OrderInfo;
import com.yfqy.app.domain.entity.OrderPayment;
import com.yfqy.app.domain.mapper.OrderInfoMapper;
import com.yfqy.app.domain.mapper.OrderPaymentMapper;
import com.yfqy.app.enums.ErrorCode;
import com.yfqy.app.enums.OrderStatus;
import com.yfqy.app.enums.PaymentStatus;
import com.yfqy.app.enums.TradeState;
import com.yfqy.app.exception.BusinessException;
import com.yfqy.app.modules.order.dto.PrepaymentDTO;
import com.yfqy.app.modules.pay.service.PayService;
import com.yfqy.app.modules.wechat.model.WechatPayOrderRequest;
import com.yfqy.app.modules.wechat.model.WechatPayOrderResponse;
import com.yfqy.app.modules.wechat.service.WechatPayService;
import com.yfqy.app.modules.wechat.util.XMLUtil;
import com.yfqy.app.security.login.LoginUserInfo;
import com.yfqy.app.util.AuthUserContext;
import com.yfqy.app.util.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    @Resource
    private OrderPaymentMapper orderPaymentMapper;
    @Resource
    private OrderInfoMapper orderInfoMapper;
    @Resource(name = "singleRedisClient")
    private RedissonClient redissonClient;
    @Resource
    private WechatPayService wechatPayService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> generateJsApiPrePay(PrepaymentDTO prepayment) {
        Map<String, Object> result = new HashMap<>();

        // 1. 先进行不需要加锁的验证
        validateUser();
        OrderInfo orderInfo = validateAndGetOrder(prepayment.getOrderId());
        // 2. 获取锁
        RLock orderStatusLock = acquireLockForOrderStatus(prepayment.getOrderId());

        try {
            Map<String, String> jsApiParams;
            OrderPayment orderPayment = getOrderPaymentFromDb(prepayment.getOrderId());
            if (orderPayment != null) {
                jsApiParams = XMLUtil.parseXmlToMap(orderPayment.getPrepayId());
            } else {
                // 3. 创建微信支付订单
                WechatPayOrderResponse orderResponse = createWechatPayOrder(orderInfo);

                // 4. 处理微信响应
                jsApiParams = processWechatResponse(orderResponse);

                // 5. 保存支付记录（数据库操作，相对较快）
                saveOrderPayment(prepayment, orderInfo, jsApiParams);
            }

            // 6. 构建结果
            buildSuccessResult(result, jsApiParams);

        } catch (BusinessException e) {
            log.warn("业务异常，orderId: {}", prepayment.getOrderId(), e);
            throw e;
        } catch (Exception e) {
            log.error("生成微信预支付订单异常，orderId: {}", prepayment.getOrderId(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "生成微信预支付订单异常");
        } finally {
            releaseLockSafely(orderStatusLock);
        }

        return result;
    }

    @Override
    public String orderquery(String orderNo) {
        WechatPayOrderResponse response = wechatPayService.queryOrder(orderNo);
        if ("SUCCESS".equals(response.getReturnCode())) {
            // 交易成功判断条件： return_code、result_code和trade_state都为SUCCESS
            if ("SUCCESS".equals(response.getResultCode())) {
                return TradeState.getTradeStateDesc(response.getTradeState());
            }
        }
        return response.getReturnCode();
    }

    private OrderPayment getOrderPaymentFromDb(Long orderId) {
        return orderPaymentMapper.selectByOrderId(orderId);
    }

    /**
     * 验证用户（不需要加锁）
     */
    private void validateUser() {
        LoginUserInfo localAuthUser = AuthUserContext.getLocalAuthUser();
        if (localAuthUser == null || Objects.equals(localAuthUser.getId(), GeneralConstants.DEFAULT_USER_ID)) {
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN);
        }
    }

    /**
     * 验证订单基本信息（不需要加锁）
     */
    private OrderInfo validateAndGetOrder(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectByPrimaryKey(orderId);
        if (orderInfo == null) {
            throw new BusinessException(ErrorCode.ORDER_NOT_EXIST);
        }
        if (!Objects.equals(orderInfo.getOrderStatus(), OrderStatus.PENDING_PAYMENT.getStatus())) {
            throw new BusinessException(ErrorCode.ORDER_STATUS_INVALID);
        }
        return orderInfo;
    }

    /**
     * 获取订单状态锁（只在必要时加锁）
     */
    private RLock acquireLockForOrderStatus(Long orderId) {
        RLock lock = redissonClient.getLock(RedisKeyConstants.ORDER_STATUS_LOCK + orderId);
        boolean lockAcquired;
        try {
            // 短时间锁，只保护状态检查
            lockAcquired = lock.tryLock(1, 3, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "获取锁中断");
        }

        if (!lockAcquired) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        return lock;
    }

    /**
     * 创建微信支付订单（网络调用，在锁外）
     */
    private WechatPayOrderResponse createWechatPayOrder(OrderInfo orderInfo) {
        WechatPayOrderRequest request = WechatPayOrderRequest.builder()
                .outTradeNo(orderInfo.getOrderNo())
                .body("一帆晴远-付款下单")
                .totalFee(orderInfo.getPaymentAmount().multiply(BigDecimal.valueOf(100)).intValue())
                .openid(AuthUserContext.getLocalAuthUser().getOpenid())
                .timeExpire(sdf.format(orderInfo.getPayExpireTime()))
                .detail(JSON.stringify(orderInfo))
                .build();

        return wechatPayService.createOrder(request);
    }

    /**
     * 处理微信响应（快速操作）
     */
    private Map<String, String> processWechatResponse(WechatPayOrderResponse orderResponse) {
        if (orderResponse == null) {
            log.warn("创建支付订单返回null");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "生成微信预支付订单异常");
        }

        if (!"SUCCESS".equals(orderResponse.getReturnCode()) || !"SUCCESS".equals(orderResponse.getResultCode())) {
            log.warn("微信支付返回失败，returnMsg: {}, errCodeDes: {}",
                    orderResponse.getReturnMsg(), orderResponse.getErrCodeDes());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "支付失败");
        }

        return wechatPayService.generateJsApiParams(orderResponse.getPrepayId());
    }

    /**
     * 保存支付记录（数据库操作）
     */
    private void saveOrderPayment(PrepaymentDTO prepayment, OrderInfo orderInfo, Map<String, String> jsApiParams) {
        OrderPayment orderPayment = OrderPayment.builder()
                .orderId(prepayment.getOrderId())
                .orderNo(orderInfo.getOrderNo())
                .paymentType((byte) 2)
                .paymentMethod("JSAPI")
                .paymentAmount(orderInfo.getPaymentAmount())
                .paymentStatus(PaymentStatus.IN_PAYMENT.getStatus())
                .prepayId(XMLUtil.convertMapToXml(jsApiParams))
                .expireTime(orderInfo.getPayExpireTime())
                .clientIp(prepayment.getClientIp())
                .deviceInfo(prepayment.getDeviceInfo())
                .remark(orderInfo.getRemark())
                .build();

        orderPaymentMapper.insert(orderPayment);
    }

    /**
     * 构建成功结果
     */
    private void buildSuccessResult(Map<String, Object> result, Map<String, String> jsApiParams) {
        result.put("success", true);
        result.put("data", jsApiParams);
        result.put("message", "生成支付参数成功");
    }

    /**
     * 安全释放锁
     */
    private void releaseLockSafely(RLock lock) {
        if (lock == null) return;

        try {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        } catch (IllegalMonitorStateException e) {
            log.warn("释放锁异常，可能锁已自动释放", e);
        }
    }
}
